package com.xhtt.modules.task.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhtt.common.exception.RRException;
import com.xhtt.common.utils.CopyUtils;
import com.xhtt.common.utils.PageUtils;
import com.xhtt.common.utils.Query;
import com.xhtt.common.utils.SerialUtils;
import com.xhtt.modules.cfg.entity.CfgComprod;
import com.xhtt.modules.cfg.entity.CfgIsland;
import com.xhtt.modules.cfg.entity.CfgStand;
import com.xhtt.modules.cfg.service.CfgComprodService;
import com.xhtt.modules.cfg.service.CfgIslandService;
import com.xhtt.modules.cfg.service.CfgStandService;
import com.xhtt.modules.sys.entity.SysUserEntity;
import com.xhtt.modules.sys.service.SysDeptService;
import com.xhtt.modules.sys.service.SysUserService;
import com.xhtt.modules.task.dao.TaskCarPlanMapper;
import com.xhtt.modules.task.entity.TaskCarPlan;
import com.xhtt.modules.task.entity.TaskCarSeo;
import com.xhtt.modules.task.entity.TaskCarSeoLog;
import com.xhtt.modules.task.entity.TaskCarTask;
import com.xhtt.modules.task.event.AfterCarPlanEvent;
import com.xhtt.modules.task.model.car.WaitingPlanModel;
import com.xhtt.modules.task.service.TaskCarPlanService;
import com.xhtt.modules.task.service.TaskCarSeoLogService;
import com.xhtt.modules.task.service.TaskCarSeoService;
import com.xhtt.modules.task.service.TaskCarTaskService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 排车计划 服务实现类
 * </p>
 *
 * @author feipc
 * @since 2019-02-27
 */
@Service
public class TaskCarPlanServiceImpl extends ServiceImpl<TaskCarPlanMapper, TaskCarPlan> implements TaskCarPlanService {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private CfgComprodService cfgComprodService;
    @Resource
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private CfgStandService cfgStandService;
    @Autowired
    private CfgIslandService cfgIslandService;
    @Autowired
    private SysDeptService sysDeptService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private TaskCarSeoService taskCarSeoService;
    @Autowired
    private TaskCarSeoLogService taskCarSeoLogService;
    @Autowired
    private TaskCarTaskService taskCarTaskService;


    @Override
    public PageUtils planList(Map<String, Object> params) {
        Page<TaskCarPlan> page = new Query<TaskCarPlan>(params).getPage();
        page.setRecords(baseMapper.planList(page, params));
        return new PageUtils(page);
    }

    @Override
    public synchronized void addPlan(TaskCarPlan taskCarPlan) {
        Integer productId = taskCarPlan.getProductId();
        Integer standId = taskCarPlan.getStageId();//台
        CfgStand stand = cfgStandService.getById(standId);//台
        CfgIsland island = cfgIslandService.getById(stand.getIslandId());//岛
        Integer pId = transactionTemplate.execute(transactionStatus -> {
            try {
                String noS = "CA" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
                TaskCarPlan db = this.getOne(new LambdaQueryWrapper<TaskCarPlan>().likeRight(TaskCarPlan::getSerialNo, noS).orderByDesc(TaskCarPlan::getSerialNo));
                String serialNo = null == db ? "" : db.getSerialNo();
                noS = SerialUtils.getSerialNo(noS, null == db, serialNo);

                taskCarPlan.setSerialNo(noS);
                this.save(taskCarPlan);
//                //要是岛上没人(或者岛上的人下班了（不在线）)，就给分配一个装车组里面在 上班中的 闲人 （空闲时间最长的那个人，并且能操作这个产品的） 真是日了狗的需求啊
//                int loginStatus = 0;
//                if (null != island.getUserId()) {
//                    SysUserEntity u = sysUserService.getOne(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getUserId, island.getUserId()));
//                    if (null != u) {
//                        loginStatus = u.getLoginStatus().intValue();
//                    }
//                }
//                if (null == island.getUserId() || 1 != loginStatus) {
//                    SysDeptEntity team = sysDeptService.getOne(new LambdaQueryWrapper<SysDeptEntity>().eq(SysDeptEntity::getType, 2).eq(SysDeptEntity::getName, "装车组").select(SysDeptEntity::getDeptId));
//                    if (null == team) {
//                        logger.error("没有装车组");
//                    } else {
//                        //获取组内上班的人
//                        List<SysUserEntity> userList = sysUserService.list(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getTeamId, team.getDeptId()).eq(SysUserEntity::getLoginStatus, 1).select(SysUserEntity::getUserId));
//                        if (CollectionUtils.isNotEmpty(userList)) {
//                            List<UserIdProdFreeTime> upfs = new ArrayList<>();
//                            userList.forEach(sysUserEntity -> {
//                                UserIdProdFreeTime upt = new UserIdProdFreeTime();
//                                upt.setUserId(sysUserEntity.getUserId().intValue());
//                                upfs.add(upt);
//                            });
//                            //获取每个人的操作产品
//                            List<SysUserProduct> ups = sysUserProductService.list(new LambdaQueryWrapper<SysUserProduct>().in(SysUserProduct::getUserId, userList.stream().map(SysUserEntity::getUserId).collect(Collectors.toList())));
//                            for (UserIdProdFreeTime upf : upfs) {
//                                List<Integer> productIds = ups.stream().filter(p -> p.getUserId().intValue() == upf.getUserId().intValue()).map(p -> p.getProductId()).collect(Collectors.toList());//获取单个人能操作的产品ids
//                                upf.setProductIds(productIds);//获取每个人的操作产品
//                                //获取每个人的空闲时间
//                                LocalDateTime time = taskCarTaskService.getUserFinishTime(upf.getUserId());
//                                if (LocalDateTime.MIN.equals(time)) {
//                                    upf.setFreeTime(Long.MAX_VALUE);//没做过任务
//                                } else if (null == time) {
//                                    upf.setFreeTime(-1);//没空
//                                } else {
//                                    LocalDateTime now = LocalDateTime.now();
//                                    Duration d = Duration.between(time, now);
//                                    long mins = d.toMinutes();//相差分钟数
//                                    upf.setFreeTime(mins);
//                                }
//                            }
//                            //按空闲时间长短倒序
//                            Collections.sort(upfs, (o1, o2) -> {
//                                if (o1.getFreeTime() > o2.getFreeTime()) {
//                                    return 1;
//                                } else {
//                                    return -1;
//                                }
//                            });
//
//                            //最后 找人 来做
//                            Iterator<UserIdProdFreeTime> it_s = upfs.iterator();
//                            while (it_s.hasNext()) {
//                                UserIdProdFreeTime i = it_s.next();
//                                if (i.getFreeTime() > 0 && (i.getProductIds().contains(0) || i.getProductIds().contains(productId)))//如果这个人空闲 并且 （是全能的 或者正好这车的产品都能操作），那就让他去这个岛吧
//                                {
//                                    island.setUserId(i.getUserId());
//                                    cfgIslandService.updateById(island);
//                                    break;
//                                }
//                            }
//
//                        }
//
//                    }
//                }

                Integer planId = taskCarPlan.getId();

                AfterCarPlanEvent event = new AfterCarPlanEvent(planId);
                applicationContext.publishEvent(event);
                return planId;
            } catch (Throwable e) {
                e.printStackTrace();
                transactionStatus.setRollbackOnly();
                return null;
            }

        });
        if (null != pId) {
            //自动排车一下
            //获取这个台 和岛上的人，2者缺一不可，都满足就排一下车
//            List<CfgStand> standList = new ArrayList<>();
//            standList.add(stand);
//            if (null != stand && null != stand.getIslandId()) {
//
//                if (null != island && null != island.getUserId()) {
//                    taskExecutor.submit(() -> rowCarSchedule.pushRowCarTask(island.getUserId(), standList));
//                }
//            }

        }

    }

    @EventListener
//    @Async
    void listenPlanCreate(AfterCarPlanEvent event) {
        event.createSub();
    }

    @Override
    public void updatePlan(TaskCarPlan taskCarPlan) {
        Integer id = taskCarPlan.getId();
        if (null == id) {
            throw new RRException("参数不正确");
        }
        TaskCarPlan db = this.getById(id);
        if (null == db) {
            throw new RRException("对象不存在");
        }
        CopyUtils.copyProperties(taskCarPlan, db);
        this.updateById(db);

        //自动排车一下
        //获取这个台 和岛上的人，2者缺一不可，都满足就排一下车
//        Integer standId = taskCarPlan.getStageId();//台
//        List<CfgStand> standList = new ArrayList<>();
//        CfgStand stand = cfgStandService.getById(standId);//台
//        standList.add(stand);
//        if (null != stand && null != stand.getIslandId()) {
//            CfgIsland island = cfgIslandService.getById(stand.getIslandId());//岛
//            if (null != island && null != island.getUserId()) {
//                taskExecutor.submit(() -> rowCarSchedule.pushRowCarTask(island.getUserId(), standList));
//            }
//        }
    }

    @Override
    public PageUtils coreList(Map<String, Object> params) {
        Page<TaskCarPlan> page = new Query<TaskCarPlan>(params).getPage();
        page.setRecords(baseMapper.coreList(page, params));
        return new PageUtils(page);
    }

    @Override
    public List<WaitingPlanModel> getAllWaitingPlans() {
        return baseMapper.getAllWaitingPlans();
    }

    @Override
    @Transactional
    public String addPlanFromOut(TaskCarPlan taskCarPlan) {
        String stageName = taskCarPlan.getStageName();
        if (StringUtils.isEmpty(stageName)) {
            throw new RRException("装车台不能为空");
        }
        String productName = taskCarPlan.getProductName();
        if (StringUtils.isEmpty(productName)) {
            throw new RRException("产品不能为空");
        }

        CfgStand stand = cfgStandService.getOne(new LambdaQueryWrapper<CfgStand>().eq(CfgStand::getName, stageName).eq(CfgStand::getStatus, 1));
        if (null == stand) {
            throw new RRException("无效的装车台");
        }
        taskCarPlan.setStageId(stand.getId());

        CfgComprod cfgComprod = cfgComprodService.getByName(productName);
        if (null == cfgComprod) {
            throw new RRException("无效的产品");
        }
        taskCarPlan.setProductId(cfgComprod.getId());

        String noS = "CA" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
        TaskCarPlan db = this.getOne(new LambdaQueryWrapper<TaskCarPlan>().likeRight(TaskCarPlan::getSerialNo, noS).orderByDesc(TaskCarPlan::getSerialNo));
        String serialNo = null == db ? "" : db.getSerialNo();
        noS = SerialUtils.getSerialNo(noS, null == db, serialNo);

        taskCarPlan.setSerialNo(noS);
        this.save(taskCarPlan);
        Integer planId = taskCarPlan.getId();

        TaskCarTask t = new TaskCarTask();
        t.setCarPlanId(planId);
        taskCarTaskService.save(t);

        return noS;
    }

    @Override
    public PageUtils seoList(Map<String, Object> params) {
        Page<TaskCarSeo> page = new Query<TaskCarSeo>(params).getPage();
        page.setRecords(baseMapper.seoList(page, params));
        return new PageUtils(page);
    }

    @Override
    public TaskCarSeo dataToSeo(Integer carPlanId) {
        return baseMapper.dataToSeo(carPlanId);
    }

    @Override
    @Transactional
    public void seoEdit(TaskCarSeo seo, SysUserEntity user) {
        taskCarSeoService.updateById(seo);
        TaskCarSeoLog seoLog = new TaskCarSeoLog();
        seoLog.setId(seo.getId());
        seoLog.setUserId(user.getUserId().intValue());
        seoLog.setUserName(user.getName());
        taskCarSeoLogService.save(seoLog);

    }

}
